#ifndef __HTTPREQUEST_H__
#define __HTTPREQUEST_H__

#include "Spark/Utils/TimePoint.h"
#include <unordered_map>
#include <assert.h>

enum class Method : int
{
    kInvalid,
    kGet,
    kPost,
    kHead,
    kPut,
    kDelete
};

enum class Version : int
{
    kUnknown,
    kHttp10,
    kHttp11
};

class HttpRequest
{
    using HeaderMap = std::unordered_map<std::string, std::string>;

  public:
    HttpRequest()
    {
    }

    void setVersion(Version v)
    {
        version_ = v;
    }

    Version getVersion() const
    {
        return version_;
    }

    HttpRequest& setMethod(const char* start, const char* end);

    Method method() const
    {
        return method_;
    }

    const char* methodString() const
    {
        const char* result = "UNKNOWN";
        switch (method_)
        {
            case Method::kGet:
                result = "GET";
                break;
            case Method::kPost:
                result = "POST";
                break;
            case Method::kHead:
                result = "HEAD";
                break;
            case Method::kPut:
                result = "PUT";
                break;
            case Method::kDelete:
                result = "DELETE";
                break;
            default:
                break;
        }
        return result;
    }

    void setPath(const char* start, const char* end)
    {
        path_.assign(start, end);
    }

    const std::string& path() const
    {
        return path_;
    }

    void setQuery(const char* start, const char* end)
    {
        query_.assign(start, end);
    }

    const std::string& query() const
    {
        return query_;
    }

    void setReceiveTime(TimePoint t)
    {
        receiveTime_ = t;
    }

    TimePoint receiveTime() const
    {
        return receiveTime_;
    }

    void addHeader(const char* start, const char* colon, const char* end)
    {
        std::string field(start, colon);
        ++colon;
        while (colon < end && ::isspace(*colon))
        {
            ++colon;
        }
        std::string value(colon, end);
        while (!value.empty() && isspace(value[value.size() - 1]))
        {
            value.resize(value.size() - 1);
        }
        headers_[field] = value;
    }

    std::string getHeader(const std::string& field) const
    {
        std::string result;
        auto it = headers_.find(field);
        if (it != headers_.end())
        {
            result = it->second;
        }
        return result;
    }

    const HeaderMap& headers() const
    {
        return headers_;
    }

    void swap(HttpRequest& that)
    {
        std::swap(method_, that.method_);
        std::swap(version_, that.version_);
        path_.swap(that.path_);
        query_.swap(that.query_);
        receiveTime_.swap(that.receiveTime_);
        headers_.swap(that.headers_);
    }

    operator bool() const
    {
        return method_ != Method::kInvalid;
    }

  private:
    Method method_{Method::kInvalid};
    Version version_;
    std::string path_;
    std::string query_;
    TimePoint receiveTime_;
    HeaderMap headers_;
};

#endif  // __HTTPREQUEST_H__